package com.ruoyi.biz.service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.MapUtils;
import com.ruoyi.biz.excel.WagesListener;
import com.ruoyi.biz.model.excel.BizWagesExcel;
import com.ruoyi.biz.model.req.BizWagesReq;
import com.ruoyi.biz.model.resp.BizWagesResp;
import com.ruoyi.common.constant.RoleConstants;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;

import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.web.convert.WagesConvert;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.biz.mapper.BizWagesMapper;
import com.ruoyi.biz.domain.BizWages;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import static com.ruoyi.common.utils.SecurityUtils.getUserId;


/**
 * 工资条Service业务层处理
 *
 * @author tianl
 * @date 2025-01-06
 */
@Service
public class BizWagesService extends ServiceImpl<BizWagesMapper, BizWages> {
    @Autowired
    private SysUserMapper sysUserMapper;

    /**
     * 分页查询工资条
     */
    public IPage<BizWagesResp> listPage(BizWagesReq req) {
        if (!SecurityUtils.hasRoles(RoleConstants.ROLE_CEO, RoleConstants.ROLE_FINANCE)) {
            req.setUserId(getUserId());
        }
        return baseMapper.list(PageUtils.page(), req);
    }

    /**
     * 查询工资条列表
     */
    public List<BizWagesResp> list(BizWagesReq req) {
        if (!SecurityUtils.hasRoles(RoleConstants.ROLE_CEO, RoleConstants.ROLE_FINANCE)) {
            req.setUserId(getUserId());
        }
        return baseMapper.list(req);
    }

    public List<BizWagesResp> listExcel(BizWagesReq req) {
        if (!SecurityUtils.hasRoles(RoleConstants.ROLE_CEO, RoleConstants.ROLE_FINANCE)) {
            req.setUserId(getUserId());
        }
        return baseMapper.listExcel(req);
    }

    @Transactional(rollbackFor = Exception.class)
    public String importExcel(MultipartFile file, String time, Boolean isUpdateSupport) {
        List<BizWagesExcel> list = new ArrayList<>();
        try {
            EasyExcel.read(file.getInputStream(), BizWagesExcel.class, new WagesListener(list))
                    .headRowNumber(4)
                    .sheet().doReadSync();
        } catch (Exception e) {
            throw new ServiceException("EXCEL解析失败！");
        }
        if (CollectionUtils.isEmpty(list)) {
            throw new ServiceException("导入数据不能为空！");
        }
        int successNum = 0;
        int failureNum = 0;
        StringBuilder failureMsg = new StringBuilder();
        for (int i = 0; i < list.size(); i++) {
            BizWagesExcel bizWagesExcel = list.get(i);
            try {
                if (StringUtils.isBlank(bizWagesExcel.getUserCode())) {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、" + "第" + (i + 4) + "行" + bizWagesExcel.getUserName() + "用户编码不能为空！");
                    continue;
                }
                SysUser sysUser = sysUserMapper.checkUserCodeUnique(bizWagesExcel.getUserCode());
                if (sysUser == null) {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、" + "第" + (i + 4) + "行" + bizWagesExcel.getUserName() + "用户编码[" + bizWagesExcel.getUserCode() + "]未匹配到用户！");
                    continue;
                }
                // 验证是否存在这个用户
                BizWages old = baseMapper.getByTimeUser(sysUser.getUserId(), time);
                if (old == null) {
                    BizWages bizWages = WagesConvert.INSTANCE.toEntity(bizWagesExcel);
                    bizWages.setTime(time);
                    bizWages.setUserId(sysUser.getUserId());
                    saveOrUpdate(bizWages);
                    successNum++;
                } else if (isUpdateSupport) {
                    BizWages bizWages = WagesConvert.INSTANCE.toEntity(bizWagesExcel);
                    bizWages.setId(old.getId());
                    bizWages.setTime(old.getTime());
                    bizWages.setUserId(old.getUserId());
                    saveOrUpdate(bizWages);
                    successNum++;
                } else {
                    failureNum++;
                    failureMsg.append("<br/>" + failureNum + "、" + "第" + (i + 4) + "行" + bizWagesExcel.getUserName() + "的" + time + "工资条已存在");
                }
            } catch (Exception e) {
                failureNum++;
                String msg = "<br/>" + failureNum + "、" + "第" + (i + 4) + "行" + bizWagesExcel.getUserName() + " 导入失败：";
                failureMsg.append(msg + e.getMessage());
                log.error(msg, e);
            }
        }
        if (failureNum > 0) {
            failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
            throw new ServiceException(failureMsg.toString());
        } else {
            return "恭喜您，数据已全部导入成功！共 " + successNum + " 条。";
        }
    }

    public Map sum(List<BizWagesResp> list, String time) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
        Map<String, Object> map = MapUtils.newHashMap();
        map.put("year", time.split("-")[0]);
        map.put("month", time.split("-")[1]);
        map.put("date", sdf.format(new Date()));
        BigDecimal hjbaseWages = list.stream().map(BizWagesResp::getBaseWages)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjmonth = list.stream().map(BizWagesResp::getMonth)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjadvance = list.stream().map(BizWagesResp::getAdvance)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjseniority = list.stream().map(BizWagesResp::getSeniority)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjpost = list.stream().map(BizWagesResp::getPost)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjcompetition = list.stream().map(BizWagesResp::getCompetition)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjsecrecy = list.stream().map(BizWagesResp::getSecrecy)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjsafe = list.stream().map(BizWagesResp::getSafe)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjjob = list.stream().map(BizWagesResp::getJob)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjteach = list.stream().map(BizWagesResp::getTeach)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjother = list.stream().map(BizWagesResp::getOther)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjholiday = list.stream().map(BizWagesResp::getHoliday)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjovertime = list.stream().map(BizWagesResp::getOvertime)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjtotalAll = list.stream().map(BizWagesResp::getTotalAll)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjsubWithholding = list.stream().map(BizWagesResp::getSubWithholding)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjsubAdvance = list.stream().map(BizWagesResp::getSubAdvance)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjsubLeave = list.stream().map(BizWagesResp::getSubLeave)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjtotalShould = list.stream().map(BizWagesResp::getTotalShould)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjsubTax = list.stream().map(BizWagesResp::getSubTax)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjsubOther = list.stream().map(BizWagesResp::getSubOther)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjtotalReal = list.stream().map(BizWagesResp::getTotalReal)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal hjtotalAdvance = list.stream().map(BizWagesResp::getTotalAdvance)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        map.put("hjbaseWages", hjbaseWages);
        map.put("hjmonth", hjmonth);
        map.put("hjadvance", hjadvance);
        map.put("hjseniority", hjseniority);
        map.put("hjpost", hjpost);
        map.put("hjcompetition", hjcompetition);
        map.put("hjsecrecy", hjsecrecy);
        map.put("hjsafe", hjsafe);
        map.put("hjjob", hjjob);
        map.put("hjteach", hjteach);
        map.put("hjother", hjother);
        map.put("hjholiday", hjholiday);
        map.put("hjovertime", hjovertime);
        map.put("hjtotalAll", hjtotalAll);
        map.put("hjsubWithholding", hjsubWithholding);
        map.put("hjsubAdvance", hjsubAdvance);
        map.put("hjsubLeave", hjsubLeave);
        map.put("hjtotalShould", hjtotalShould);
        map.put("hjsubTax", hjsubTax);
        map.put("hjsubOther", hjsubOther);
        map.put("hjtotalReal", hjtotalReal);
        map.put("hjtotalAdvance", hjtotalAdvance);
        return map;
    }

    /**
     * 根据ID查询
     */
    public BizWagesResp selectById(Long id) {
        return baseMapper.selectDetail(id);
    }

    /**
     * 新增修改工资条
     */
    @Transactional(rollbackFor = Exception.class)
    public void beforeSave(BizWages bizWages) {
        if (bizWages.getId() != null) {
            bizWages.setUpdateTime(DateUtils.getNowDate());
        } else {
            bizWages.setCreateTime(DateUtils.getNowDate());
            bizWages.setUpdateTime(DateUtils.getNowDate());
            BizWages old = baseMapper.getByTimeUser(bizWages.getUserId(), bizWages.getTime());
            if (old != null) {
                throw new ServiceException("该用户当月已存在工资条");
            }
        }
        BigDecimal totalAll = BigDecimal.ZERO;
        if (bizWages.getBaseWages() != null) {
            totalAll = totalAll.add(bizWages.getBaseWages());
        }
        if (bizWages.getMonth() != null) {
            totalAll = totalAll.add(bizWages.getMonth());
        }
        if (bizWages.getAdvance() != null) {
            totalAll = totalAll.add(bizWages.getAdvance());
        }
        if (bizWages.getSeniority() != null) {
            totalAll = totalAll.add(bizWages.getSeniority());
        }
        if (bizWages.getPost() != null) {
            totalAll = totalAll.add(bizWages.getPost());
        }
        if (bizWages.getCompetition() != null) {
            totalAll = totalAll.add(bizWages.getCompetition());
        }
        if (bizWages.getSecrecy() != null) {
            totalAll = totalAll.add(bizWages.getSecrecy());
        }
        if (bizWages.getSafe() != null) {
            totalAll = totalAll.add(bizWages.getSafe());
        }
        if (bizWages.getJob() != null) {
            totalAll = totalAll.add(bizWages.getJob());
        }
        if (bizWages.getTeach() != null) {
            totalAll = totalAll.add(bizWages.getTeach());
        }
        if (bizWages.getOther() != null) {
            totalAll = totalAll.add(bizWages.getOther());
        }
        if (bizWages.getHoliday() != null) {
            totalAll = totalAll.add(bizWages.getHoliday());
        }
        if (bizWages.getOvertime() != null) {
            totalAll = totalAll.add(bizWages.getOvertime());
        }
        bizWages.setTotalAll(totalAll);
        BigDecimal totalShould = totalAll;
        if (bizWages.getSubWithholding() != null) {
            totalShould = totalShould.subtract(bizWages.getSubWithholding());
        }
        if (bizWages.getSubAdvance() != null) {
            totalShould = totalShould.subtract(bizWages.getSubAdvance());
        }
        if (bizWages.getSubLeave() != null) {
            totalShould = totalShould.subtract(bizWages.getSubLeave());
        }
        bizWages.setTotalShould(totalShould);
        BigDecimal totalReal = totalShould;
        if (bizWages.getSubTax() != null) {
            totalReal = totalReal.subtract(bizWages.getSubTax());
        }
        if (bizWages.getSubOther() != null) {
            totalReal = totalReal.subtract(bizWages.getSubOther());
        }
        bizWages.setTotalReal(totalReal);
        saveOrUpdate(bizWages);
    }

    /**
     * 批量删除工资条
     */
    @Transactional(rollbackFor = Exception.class)
    public int deleteByIds(Long[] ids) {
        return baseMapper.deleteBatchIds(Arrays.asList(ids));
    }

}
